home *** CD-ROM | disk | FTP | other *** search
/ Floppyshop 2 / Floppyshop - 2.zip / Floppyshop - 2.iso / art&graf.ix / art-3485 / art-5110 / ximg1311 / ximgsnap.c < prev    next >
C/C++ Source or Header  |  1995-07-06  |  19KB  |  642 lines

  1. /* (X)IMG snapshot utility (c) 1994 by Eero Tamminen
  2.  * (puujalka@modeemi.cs.tut.fi)
  3.  *
  4.  * (X)IMG line packing function (c) 1994 by Thomas Binder
  5.  * (binder@rbg.informatik.th-darmstadt.de)
  6.  */
  7.  
  8. /* ++tb on 05/15/95:
  9.  * - some small patches to make Pure C and other more-ANSI-like
  10.  *   compilers happy
  11.  * - added MagiC-workaround
  12.  * - fixed wrong error-handling in Fwrite-calls
  13.  * - fixed small bug: Mouse was missing when the alert after saving
  14.  *   the snapshot appeared
  15.  * - fixed getaccenv
  16.  * - removed menu_id from main because it was never used
  17.  */
  18.  
  19. #include <osbind.h>    /* pterm() */
  20. #include <string.h>    /* memcpy(), strcpy() etc. */
  21. #include <stdlib.h>    /* getenv() */
  22.  
  23. /* system includes */
  24. #ifdef __GNUC__
  25. #include <aesbind.h>
  26. #include <vdibind.h>
  27. typedef signed short   WORD;
  28. typedef unsigned short UWORD;
  29. #endif
  30. #ifdef __PUREC__
  31. #include <aes.h>
  32. #include <vdi.h>
  33. #include <portab.h>
  34. #define short    int
  35. short    gl_apid;
  36. #endif
  37. #ifdef __SOZOBONX__
  38. #include <xgemfast.h>    /* AES / VDI      */
  39. #endif
  40.  
  41. extern short _app;
  42.  
  43. #ifndef FALSE
  44. #define FALSE 0
  45. #define TRUE  !FALSE
  46. #endif
  47.  
  48. /* define some texts */
  49. #define ACC_NAME  "  (X)IMG Snapshot "
  50. #define ALERT_AREA  "[2][ (X)IMG-SNAPSHOT v1.1 |1995 (C) Eero Tamminen | | Area to be saved... |][Freehand|Window|Screen]"
  51. #define ALERT_COLOR  "[1][|Only 2-256 color modes... |][  OK  ]"
  52. #define ALERT_DONE  "[1][|Image saved. |][  OK  ]"
  53. #define ALERT_SAVE  "[3][|Save failed! |][ Hmm... ]"
  54.  
  55. struct BLOCK
  56. {
  57.   short x1;    /* 1st corner    */
  58.   short y1;
  59.   short x2;    /* size / 2nd corner  */
  60.   short y2;
  61. };
  62.  
  63. /* define GEM image */
  64. typedef struct IMG_HEADER
  65. {                 /* Header of GEM Image Files   */
  66.   short version;  /* Img file format version (1) */
  67.   short length;   /* Header length in words  (8) */
  68.   short planes;   /* Number of bit-planes    (1) */
  69.   short pat_len;  /* length of Patterns      (2) */
  70.   short pix_w;    /* Pixel width in 1/1000 mmm  (372)    */
  71.   short pix_h;    /* Pixel height in 1/1000 mmm (372)    */
  72.   short img_w;    /* Pixels per line (=(x+7)/8 Bytes)    */
  73.   short img_h;    /* Total number of lines               */
  74.   long  magic;    /* Contains "XIMG" if standard color   */
  75.   short paltype;  /* palette type (0 = RGB (short each)) */
  76. } IMG_header;
  77. #define XIMG      0x58494D47L
  78.  
  79. /* ------------------------------------
  80.  * global variables
  81.  */
  82. /* some vdi arrays and global variables etc. */
  83. static short vdi_handle, work_in[11], work_out[57],
  84.       screen_planes, screen_colors,
  85.       screen_w, screen_h;
  86.  
  87. static char *save_path;
  88.  
  89. /* VDI <-> Device palette order conversion matrixes:
  90.  */
  91. /* Four-plane device-vdi */
  92. static short dev2vdi4[] = {0,2,3,6,4,7,5,8,9,10,11,14,12,15,13,1};
  93. /* Two-plane device-vdi */
  94. static short dev2vdi2[] = {0,2,3,1};
  95.  
  96. static char tmp_buf[2048];    /* temp for a line from screen */
  97. static char dst_buf[2048];    /* buf_1 converted into planar */
  98. static char pack_buf[258];    /* for 1 line/bitplane packing */
  99.  
  100. /* ------------------------------------
  101.  * Function prototypes.
  102.  */
  103. int  do_it(void);
  104. int  select_area(short *x, short *y, short *w, short *h);
  105. int  save_file(struct BLOCK *blk, char *filename);
  106. int  save_header(short header, struct BLOCK *blk);
  107. int  save_bitmaps(short header, struct BLOCK *blk);
  108. WORD pack_img_line(char *source, char *dest, WORD byte_width);
  109.  
  110. /* GEM handling functions. */
  111. void prg_init(void);
  112. char *getaccenv(const char *var);
  113. void get_savepath(char *(*get_env)(const char *var));
  114.  
  115. /* ------------------------------------
  116.  * (main loop).
  117.  */
  118. void main()
  119. {
  120.   short  mbuf[8];
  121.  
  122.   prg_init();
  123.   /* not acc -> snap and quit */
  124.   if(_app)
  125.   {
  126.     get_savepath(getenv);
  127.     do_it();
  128.     appl_exit();
  129.     Pterm(0);
  130.   }
  131.  
  132.   get_savepath(getaccenv);
  133.   menu_register(gl_apid, ACC_NAME);  /* register acc */
  134.  
  135.   /* Endless loop. */
  136.   while (TRUE)
  137.   {
  138.     evnt_mesag(mbuf);
  139.     if(mbuf[0] == AC_OPEN)
  140.       do_it();
  141.   }
  142. }
  143.  
  144. /* ------------------------------------
  145.  * Standard GEM startup.
  146.  */
  147. void prg_init()
  148. {
  149.   int i;
  150.  
  151.   gl_apid = appl_init();
  152.  
  153.   /* open virtual screen workstation (screen) */
  154.   for(i = 0; i < 10; work_in[i ++] = 1);
  155.   work_in[10] = 2;
  156.   vdi_handle = graf_handle( &i, &i, &i, &i );
  157.   v_opnvwk( work_in, &vdi_handle, work_out );
  158.   screen_colors = work_out[13];
  159.   screen_w = work_out[0];
  160.   screen_h = work_out[1];
  161.  
  162.   /* get the number of bitplanes on screen */
  163.   vq_extnd( vdi_handle, 1, work_out );
  164.   screen_planes = work_out[4];
  165.   v_clsvwk(vdi_handle);
  166. }
  167.  
  168. /* Special getenv for accessories.
  169.  * Get variables from system enviroment
  170.  * instead of the process one.
  171.  */
  172. char *getaccenv(const char *var)
  173. {
  174.   char *string;
  175.  
  176.   shel_envrn(&string, (char *)var);
  177.   if(string)
  178.   {
  179.     if(*string == '=')
  180.       return(++string);
  181.     else
  182.       return("");
  183.   }
  184.   else
  185.     return NULL;
  186. }
  187.  
  188. /* Get the file save path (=CLIPBOARD)
  189.  * As you can see, I'm in a need of some
  190.  * documentation...
  191.  */
  192. void get_savepath(char *(*get_env)(const char *var))
  193. {
  194.   char *path;
  195.  
  196.   /* where's the clipboard directory and does it's drive exist */
  197.   if((((path = (*get_env)("CLIPBRD")) != NULL)   ||
  198.       ((path = (*get_env)("SCRAPDIR")) != NULL)) &&
  199.      (Drvmap() & (1 << ((path[0] & 0xDF) - 'A')))
  200.     )
  201.     save_path = path;
  202.   else
  203.     if(Drvmap() & 4)            /* does C: exist? */
  204.       save_path = "C:\\CLIPBRD";
  205.     else
  206.       save_path = "A:\\";
  207. }
  208.  
  209. /* ---------------------
  210.  * pack and save XIMG
  211.  */
  212. int do_it()
  213. {
  214.   struct BLOCK blk;
  215.   short select, top_win, i, real_top;
  216.   int save_ok;
  217.   static int mode = 2, snap = 0;
  218.   static char filename[] = "SNAP_000.IMG";
  219.  
  220.   /* Can't handle more than 8 bitplanes */
  221.   if(screen_planes > 8)
  222.   {
  223.     form_alert(1, ALERT_COLOR);
  224.     return(FALSE);
  225.   }
  226.  
  227.   select = TRUE;
  228.   /* select area to be saved */
  229.   switch((mode = form_alert(mode, ALERT_AREA)))
  230.   {
  231.     /* draggable rubber band */
  232.     case 1:
  233.       wind_update(BEG_MCTRL);
  234.       graf_mouse(THIN_CROSS, 0);
  235.       wind_update(BEG_UPDATE);
  236.       select = select_area(&blk.x1, &blk.y1, &blk.x2, &blk.y2);
  237.       wind_update(END_UPDATE);
  238.       wind_update(END_MCTRL);
  239.       graf_mouse(ARROW, 0);
  240.       if(!select)
  241.         return(FALSE);
  242.       break;
  243.     /* get top window and it's work area (contents) */
  244.     case 2:
  245.       wind_get(0, WF_TOP, &top_win, &i, &i, &real_top);
  246.       /* ++tb: Workaround for MagiC 2, which returns -2 as top-window
  247.        * if it doesn't belong to your application (a trick to make
  248.        * some old programs run). Does not work with Pure C because of
  249.        * its `optimized' wind_get-call which ignores real_top.
  250.        */
  251.       if (top_win == -2)
  252.           top_win = real_top;
  253.       wind_get(top_win, WF_WORKXYWH, &blk.x1, &blk.y1, &blk.x2, &blk.y2);
  254.       break;
  255.     /* whole screen */
  256.     case 3:
  257.       blk.x1 = blk.y1 = 0;
  258.       blk.x2 = screen_w + 1;
  259.       blk.y2 = screen_h + 1;
  260.       break;
  261.   }
  262.  
  263.   /* filename (into current directory) */
  264.   filename[5] = snap / 100 + '0';
  265.   filename[6] = snap % 100 / 10 + '0';
  266.   filename[7] = snap % 10 + '0';
  267.   snap = ++ snap % 1000;
  268.  
  269.   graf_mouse(M_OFF, 0);
  270.   wind_update(BEG_UPDATE);
  271.   save_ok = save_file(&blk, filename);
  272.   graf_mouse(M_ON, 0);
  273.   if(save_ok)
  274.     form_alert(1, ALERT_DONE);
  275.   else
  276.     form_alert(1, ALERT_SAVE);
  277.   wind_update(END_UPDATE);
  278.  
  279.   return(TRUE);
  280. }
  281.  
  282. /* select area for saving */
  283. int select_area(short *mx, short *my, short *w, short *h)
  284. {
  285.   short button = TRUE, i;
  286.  
  287.   /* mouse off */
  288.   evnt_button(1, 1, 0, mx, my, &button, &i);
  289.   /* mouse on, co-ordinates */
  290.   evnt_button(257, 3, 0, mx, my, &button, &i);
  291.   /* right button -> cancel */
  292.   if(button == 2)
  293.     return(FALSE);
  294.  
  295.   /* get area co-ordinates */
  296.   graf_rubberbox(*mx, *my, 1, 1, w, h);
  297.   return(TRUE);
  298. }
  299.  
  300. /* save selected area into a file as an IMG */
  301. int save_file(struct BLOCK *blk, char *filename)
  302. {
  303.   short handle;
  304.   int error = FALSE;
  305.  
  306.   /* max. block width */
  307.   if(blk->x2 > 2000)
  308.     blk->x2 = 2000;
  309.  
  310.   /* CD where file is to be saved */
  311.   Dsetdrv((save_path[0] & 0xDF) - 'A');
  312.   Dsetpath(save_path);
  313.  
  314.   /* open IMG file: Use OS routines
  315.    * instead of stdio functions.
  316.    */
  317.   if((handle = (short)Fcreate(filename, (short)0)) >= 0)
  318.   {
  319.     /* open workstation */
  320.     v_opnvwk(work_in, &vdi_handle, work_out);
  321.     /* save IMG header */
  322.     if(save_header(handle, blk))
  323.     {
  324.       /* convert and save selected block line at the time */
  325.       if(!save_bitmaps(handle, blk))
  326.         error = TRUE;
  327.     }
  328.     else
  329.       error = TRUE;
  330.     /* close workstation */
  331.     v_clsvwk(vdi_handle);
  332.   }
  333.   else
  334.     error = TRUE;
  335.  
  336.   Fclose(handle);
  337.  
  338.   if(error)
  339.     return(FALSE);
  340.   else
  341.     return(TRUE);
  342. }
  343.  
  344. /* save IMG header and XIMG palette */
  345. int save_header(short handle, struct BLOCK *blk)
  346. {
  347.   IMG_header image;
  348.   short rgb[3], i, idx, error;
  349.  
  350.   /* only resolutions with a palette (<= 256 colors) */
  351.   if((screen_planes > 8) && (screen_colors != (1 << screen_planes)))
  352.     return(FALSE);
  353.  
  354.   /* setup GEM image header */
  355.   image.version = 1;              /* Img file format version (1) */
  356.   if(screen_planes == 1)
  357.     image.length  = 8;            /* Header length in words  (8) */
  358.   else
  359.     image.length  = 11 + screen_colors * 3;
  360.   image.planes  = screen_planes;  /* Number of bit-planes    (1) */
  361.   image.pat_len = 2;              /* length of Patterns      (2) */
  362.   image.pix_w   = 372;            /* Pixel width in 1/1000 mmm  (372)    */
  363.   image.pix_h   = 372;            /* Pixel height in 1/1000 mmm (372)    */
  364.   image.img_w   = blk->x2;        /* Pixels per line (=(x+7)/8 Bytes)    */
  365.   image.img_h   = blk->y2;        /* Total number of lines in picture    */
  366.   image.magic   = XIMG;           /* Contains "XIMG" if standard color   */
  367.   image.paltype = 0;              /* palette type (0 = RGB (short each)) */
  368.  
  369.   /* write IMG header info */
  370.   error = -(Fwrite(handle, 16L, (char *)&(image.version)) != 16L);
  371.  
  372.   /* if colors, add XIMG header info */
  373.   if((screen_planes > 1) && (error >= 0))
  374.   {
  375.     error = -(Fwrite(handle, 6L, (char *)&(image.magic)) != 6L);
  376.  
  377.     /* save VDI palette */
  378.     for(i = 0; i < screen_colors; i ++)
  379.     {
  380.       switch(screen_planes)
  381.       {
  382.         case 2:
  383.           idx = dev2vdi2[i];
  384.           break;
  385.         case 4:
  386.           idx = dev2vdi4[i];
  387.           break;
  388.         default:
  389.           idx = i;
  390.       }
  391.       vq_color(vdi_handle, idx, 0, rgb);
  392.       if(error < 0)
  393.         return(FALSE);
  394.       else
  395.       {
  396.         if (Fwrite(handle, 6L, (char *)(rgb)) != 6L)
  397.           return(FALSE);
  398.       }
  399.     }
  400.   }
  401.   return(TRUE);
  402. }
  403.  
  404. /* convert and save the selected area into IMG */
  405. int save_bitmaps(short handle, struct BLOCK *blk)
  406. {
  407.   static char opcode[] = {0, 0, 0xff, 0};
  408.   short bytes, packed, width, i, pxy[8], error;
  409.   int aligning = FALSE, scan_repeat = 1, compare;
  410.   MFDB screen, temp, dest;
  411.   char *buf;
  412.  
  413.   /* setup memory description blocks */
  414.   width = (blk->x2 + 15) & 0xFFF0;  /* word aligned */
  415.   screen.fd_addr  = (char *)0;
  416.   temp.fd_addr    = tmp_buf;        /* address      */
  417.   temp.fd_w       = blk->x2;        /* width        */
  418.   temp.fd_wdwidth = width >> 4;     /* width / 16   */
  419.   temp.fd_h       = 1;              /* height       */
  420.   temp.fd_stand   = 0;              /* formt=device */
  421.   temp.fd_nplanes = screen_planes;  /* bitplanes    */
  422.   dest.fd_addr    = dst_buf;
  423.   dest.fd_w       = blk->x2;
  424.   dest.fd_wdwidth = width >> 4;
  425.   dest.fd_h       = 1;
  426.   dest.fd_stand   = 1;              /* formt=planar */
  427.   dest.fd_nplanes = screen_planes;
  428.  
  429.   /* scan_repeat search length */
  430.   compare = (width >> 3) * screen_planes;
  431.   /* byte / word alignment */
  432.   bytes = (blk->x2 + 7) >> 3;
  433.   if(width != (bytes << 3))
  434.     aligning = TRUE;
  435.   width --;
  436.  
  437.   /* setup raster copy co-ordinates */
  438.   blk->y2 += blk->y1;
  439.   pxy[0] = blk->x1;
  440.   pxy[2] = blk->x1 + blk->x2 - 1;
  441.   pxy[4] = 0;
  442.   pxy[5] = 0;
  443.   pxy[6] = blk->x2 - 1;
  444.   pxy[7] = 0;
  445.   do
  446.   {
  447.     /* copy current line into buffer */
  448.     pxy[1] = pxy[3] = blk->y1;
  449.     vro_cpyfm(vdi_handle, S_ONLY, pxy, &screen, &temp);
  450.  
  451.     /* check scan_line repeat */
  452.     scan_repeat = 1;
  453.     while (pxy[1] < (blk->y2 - 1))
  454.     {
  455.       pxy[1] = ++pxy[3];
  456.       vro_cpyfm(vdi_handle, S_ONLY, pxy, &screen, &dest);
  457.       if (memcmp(dst_buf, tmp_buf, compare))
  458.         break;
  459.       scan_repeat++;
  460.     }
  461.  
  462.     if(scan_repeat > 1)
  463.     {
  464.       /* save opcodes and a line repeat count */
  465.       opcode[3] = scan_repeat;
  466.       error = -(Fwrite(handle, 4L, opcode) != 4L);
  467.     }
  468.  
  469.     /* transfrom line from device into standard (planar) format */
  470.     vr_trnfm(vdi_handle, &temp, &dest);
  471.  
  472.     /* pack and save line, plane by plane */
  473.     buf = dst_buf;
  474.     for(i = 0; i < screen_planes; i ++)
  475.     {
  476.       /* pack and save one line/plane */
  477.       packed = pack_img_line(buf, pack_buf, bytes);
  478.       error = -(Fwrite(handle, (long)packed, pack_buf) != packed);
  479.  
  480.       /* check for write errors */
  481.       if(error < 0)
  482.         return(FALSE);
  483.       else
  484.         buf += bytes;
  485.       if(aligning)      /* byte <-> word alignment  */
  486.         buf ++;
  487.     }
  488.     blk->y1 += scan_repeat;
  489.   } while (blk->y1 <= blk->y2);
  490.  
  491.   return(TRUE);
  492. }
  493.  
  494. /* --------------------------------------------------------------------
  495.  * packimg.c as of 11/02/94
  496.  *
  497.  * (c) 1994 by Thomas Binder (binder@rbg.informatik.th-darmstadt.de),
  498.  * Johann-Valentin-May-Straße 7, 64665 Alsbach-Hähnlein, Germany
  499.  *
  500.  * Contains a routine that packs a scanline for an (X)IMG-file.
  501.  *
  502.  * Permission is granted to spread this routine, but only the .c- and
  503.  * the .h-file together, *unchanged*. Permission is also granted to
  504.  * use this routine in own productions, as long as it's mentioned that
  505.  * the routine was used and that it was written by me.
  506.  *
  507.  * I can't be held responsible for the correct function of this routine,
  508.  * nor for any damage that occurs after the correct or incorrect use of
  509.  * this routine. USE IT AT YOUR OWN RISK!
  510.  *
  511.  * If you find any bugs or have suggestions, please contact me!
  512.  *
  513.  * History:
  514.  * 10/28 -
  515.  * 10/29/94: Creation
  516.  * 10/30/94: pack_img_line now also detects 2-byte-solid runs
  517.  * 10/31/94: Fixed wrong comment. pack_img_line's return value will be
  518.  *           <= byte_width + 2, not <= byte_width (because in the worst
  519.  *           case, all data of the line must be stored uncompressed as
  520.  *           a bitstring, and this needs two extra-bytes for identifying
  521.  *           the bitstring)
  522.  * 11/02/94: Fixed routine. It could happen that the saved line was even
  523.  *           longer than byte_width + 2. This should be fixed now, as
  524.  *           pack_img_line now only packs if this will *really* save
  525.  *           bytes. Thanks to Eero Tamminen for reporting that bug.
  526.  *           Another bug was in the adjustment of the new position after
  527.  *           a run was packed (this didn't cause any harm, but wasted
  528.  *           some bytes sometimes).
  529.  * 11/03/94: Solid runs can now have odd lenghts. - Eero -
  530.  *
  531.  * pack_img_line
  532.  *
  533.  * Pack one scanline for an (X)IMG-file, using 2-byte-pattern runs
  534.  * and solid runs. It's an easy task to write a second function that
  535.  * checks the packed lines for scanline runs.
  536.  *
  537.  * Input:
  538.  * source: Pointer to img-data that should be packed (one scanline
  539.  *         of one plane)
  540.  * dest: Pointer to where the packed information should be written
  541.  *       (this area will contain data that can directly be written
  542.  *       to a file after the function returns)
  543.  * byte_width: Width of the scanline in bytes
  544.  *
  545.  * Output:
  546.  * Number of bytes in dest (<= byte_width + 2)
  547.  */
  548.  
  549. WORD pack_img_line(char *source, char *dest, WORD byte_width)
  550. {
  551.   WORD  i, j, pos, last, cnt;
  552.   UWORD  test;
  553.  
  554.   byte_width --;
  555.   /* repeat until there's no more to compress (at least two bytes!). */
  556.   for(i = pos = last = 0; i < byte_width; i++)
  557.   {
  558.     /* We only check for 2-byte-patterns. If we find a run, we then
  559.      * check if the pattern is 0xffff or 0x0000. In that case, it's
  560.      * treated as a solid run, as a pattern run otherwise.
  561.      */
  562.     test = ((UWORD)source[i] << 8) | (source[i + 1] & 0xff);
  563.     cnt = 1, j = i;
  564.     while((j += 2) < byte_width &&
  565.          (((UWORD)source[j] << 8) | (source[j + 1] & 0xff)) == test)
  566.          cnt++;
  567.  
  568.     /* cnt now contains how often we could find the two-byte-pattern
  569.      * located at position i (the length of the run).
  570.      * We only use the run, if it's longer than two or can be transformed
  571.      * into a solid run (plain "black" or plain "white").
  572.      */
  573.     if(((test == 0xffff) || !test) || (cnt > 2))
  574.     {
  575.       /* The bytes between the beginning of the current and the end of the
  576.        * last run are saved as a bitstring.
  577.        */
  578.       if(last < i)
  579.       {
  580.         /* Saving as a bitstring needs two extra bytes, so we now have to
  581.          * check if we still save bytes by packing the run we've found.
  582.          */
  583.         if((test == 0xffff) || !test)
  584.         {
  585.           if(cnt < 2)
  586.             continue;
  587.         }
  588.         else
  589.         {
  590.           if(cnt < 4)
  591.             continue;
  592.         }
  593.         dest[pos++] = 0x80;
  594.         dest[pos++] = i - last;
  595.         for(j = last; j < i; dest[pos++] = source[j++]);
  596.       }
  597.       /* Adjust the current position and the end of the "last" run. */
  598.       last = i += cnt * 2;
  599.       i--; /* - 1 because of i++ in the loop. */
  600.       if((test == 0xffff) || !test)
  601.       {
  602.         /* Place a solid run */
  603.         cnt *= 2;
  604.         /* Check for odd (cnt + 1) lenght of solid run. */
  605.         if(source[last] == (test & 0xff) && i < byte_width)
  606.           last++, cnt ++, i++;
  607.         do
  608.         {
  609.           dest[pos++] = (cnt > 127) ? 127 : cnt;
  610.           if(test)
  611.             dest[pos - 1] |= 128;
  612.           cnt -= 127;
  613.         } while(cnt > 0);
  614.       }
  615.       else
  616.       {
  617.         /* Place a pattern run. */
  618.         do
  619.         {
  620.           dest[pos++] = 0;
  621.           dest[pos++] = (cnt > 127) ? 127 : cnt;
  622.           dest[pos++] = test >> 8;
  623.           dest[pos++] = test & 0xff;
  624.           cnt -= 127;
  625.         } while(cnt > 0);
  626.       }
  627.     }
  628.   }
  629.   /* If there are bytes left, put them into the destination area as a
  630.    * bitstring.
  631.    */
  632.   if(last <= byte_width)
  633.   {
  634.     dest[pos++] = 0x80;
  635.     dest[pos++] = byte_width - last + 1;
  636.     for(j = last; j <= byte_width; dest[pos++] = source[j++]);
  637.   }
  638.   /* Return the number of bytes we used in dest. */
  639.   return(pos);
  640. }
  641.  
  642. /* EOF */